package com.example.yckjbigdataservice.utils;

import com.example.yckjbigdataservice.properties.ElasticsearchProperties;
import org.elasticsearch.hwclient.LoginUtil;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Locale;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


public class ESLoginUtil {

    private static final Logger LOG = LogManager.getLogger(ESLoginUtil.class);

    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    private static final String ES = "es.";
    private static final String JAAS_POSTFIX = ".jaas.conf";
    private static final String IBM_LOGIN_MODULE = "com.ibm.security.auth.module.Krb5LoginModule required";
    private static final String SUN_LOGIN_MODULE = "com.sun.security.auth.module.Krb5LoginModule required";
    public static final String JAVA_SECURITY_LOGIN_CONF_KEY = "java.security.auth.login.config";
    private static final String JAVA_SECURITY_KRB5_CONF_KEY = "java.security.krb5.conf";
    private static final boolean IS_IBM_JDK = System.getProperty("java.vendor").contains("IBM");
    public static boolean writeFlag = false;
    private static String esJaasConfPath;

    public static void setKrb5Config(String krb5ConfFile) throws IOException {
        String ret = System.getProperty("java.security.krb5.conf");
        if (ret != null && !ret.isEmpty()) {
            if (krb5ConfFile != null && !krb5ConfFile.isEmpty() && !ret.equals(krb5ConfFile)) {
                System.setProperty("java.security.krb5.conf", krb5ConfFile);
            }
        } else {
            if (krb5ConfFile != null && !krb5ConfFile.isEmpty()) {
                System.setProperty("java.security.krb5.conf", krb5ConfFile);
                ret = System.getProperty("java.security.krb5.conf");
            }

            if (ret == null || ret.isEmpty() || !ret.equals(krb5ConfFile)) {
                LOG.error(String.format(Locale.ENGLISH, "%s is null.", "java.security.krb5.conf"));
                throw new IOException(String.format(Locale.ENGLISH, "%s is null.", "java.security.krb5.conf"));
            }
        }

    }

    public static synchronized void setJaasFile(String principal, String keytabPath, String customJaasPath) throws IOException {
        String jaasPath = customJaasPath;
        if (keytabPath == null || keytabPath.isEmpty()) {
            LOG.error("The user keytab file path is null or empty, please check the configuration.");
            throw new IOException("The user keytab file path is null or empty, please check the configuration.");
        }

        //String filePath = keytabPath.substring(0, keytabPath.lastIndexOf(File.separator));
        //jaasPath = filePath + File.separator + "es." + System.getProperty("user.name") + ".jaas.conf";
        jaasPath = jaasPath.replace("\\", "\\\\");
        keytabPath = keytabPath.replace("\\", "\\\\");
        if ((new File(jaasPath)).exists()) {
            if (!writeFlag) {
                deleteJaasFile(jaasPath);
                writeJaasFile(jaasPath, principal, keytabPath);
            }
        } else {
            writeJaasFile(jaasPath, principal, keytabPath);
        }

        if (!writeFlag) {
            System.setProperty("java.security.auth.login.config", jaasPath);
            writeFlag = true;
            LOG.debug(String.format(Locale.ENGLISH, "jaasPath is %s.", jaasPath));
            LOG.debug(String.format(Locale.ENGLISH, "keytabPath is %s.", keytabPath));
        }

        esJaasConfPath = jaasPath;
    }

    public static String getEsJaasConfPath() {
        return esJaasConfPath;
    }

    private static void writeJaasFile(String jaasPath, String principal, String keytabPath) throws IOException {
        try {

            File jaasFile = new File(jaasPath);
            if(! jaasFile.exists()){
                Files.createDirectories(Paths.get(jaasFile.getParent()));
            }
            FileWriter writer = new FileWriter(jaasFile);

            try {
                writer.write(getJaasConfContext(principal, keytabPath));
                writer.flush();
            } catch (Throwable var7) {
                try {
                    writer.close();
                } catch (Throwable var6) {
                    var7.addSuppressed(var6);
                }

                throw var7;
            }

            writer.close();
        } catch (IOException var8) {
            throw new IOException("Failed to create jaas.conf file");
        }
    }

    private static void deleteJaasFile(String jaasPath) throws IOException {
        File jaasFile = new File(jaasPath);
        if (jaasFile.exists() && !jaasFile.delete()) {
            throw new IOException("Failed to delete exists jaas file.");
        }
    }

    private static String getJaasConfContext(String principal, String keytabPath) {
        LoginUtil.Module[] allModule = LoginUtil.Module.values();
        StringBuilder builder = new StringBuilder();

        for(LoginUtil.Module modlue : allModule) {
            builder.append(getModuleContext(principal, keytabPath, modlue));
        }

        return builder.toString();
    }

    private static String getModuleContext(String userPrincipal, String keyTabPath, LoginUtil.Module module) {
        StringBuilder builder = new StringBuilder();
        if (IS_IBM_JDK) {
            builder.append(module.getName()).append(" {").append(LINE_SEPARATOR);
            builder.append("com.ibm.security.auth.module.Krb5LoginModule required").append(LINE_SEPARATOR);
            builder.append("credsType=both").append(LINE_SEPARATOR);
            builder.append("principal=\"").append(userPrincipal).append("\"").append(LINE_SEPARATOR);
            builder.append("useKeytab=\"").append(keyTabPath).append("\"").append(LINE_SEPARATOR);
            builder.append("debug=true;").append(LINE_SEPARATOR);
            builder.append("};").append(LINE_SEPARATOR);
        } else {
            builder.append(module.getName()).append(" {").append(LINE_SEPARATOR);
            builder.append("com.sun.security.auth.module.Krb5LoginModule required").append(LINE_SEPARATOR);
            builder.append("useKeyTab=true").append(LINE_SEPARATOR);
            builder.append("keyTab=\"").append(keyTabPath).append("\"").append(LINE_SEPARATOR);
            builder.append("principal=\"").append(userPrincipal).append("\"").append(LINE_SEPARATOR);
            builder.append("useTicketCache=false").append(LINE_SEPARATOR);
            builder.append("storeKey=true").append(LINE_SEPARATOR);
            builder.append("debug=true;").append(LINE_SEPARATOR);
            builder.append("};").append(LINE_SEPARATOR);
        }

        return builder.toString();
    }

    public static enum Module {
        KAFKA("KafkaClient"),
        ZOOKEEPER("Client"),
        Elasticsearch("EsClient");

        private String name;

        private Module(String name) {
            this.name = name;
        }

        public String getName() {
            return this.name;
        }
    }
}
